/*

 * pushbutton attached to pin 2 from +5V
// * 10K resistor attached to pin 2 from ground
 * LCD RS pin to digital pin 12
 * LCD Enable pin to digital pin 11
 * LCD D4 pin to digital pin 7
 * LCD D5 pin to digital pin 6
 * LCD D6 pin to digital pin 5
 * LCD D7 pin to digital pin 4
 * LCD R/W pin to ground
 * 10K resistor:
 * ends to +5V and ground
 * wiper to LCD VO pin (pin 3)
 */

// include the library code:
#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 7, 6, 5, 4);
 
// constants won't change. They're used here to 
// set pin numbers:
const int buttonPin = 2;     // the number of the pushbutton pin
const int ledPin =  13;      // the number of the LED pin
const int shutter = 8;       // Emplacement du shutter (pin de commande du transistor)

// variables will change:
int buttonState = 0;              // variable for reading the pushbutton status
int oldButtonState = buttonState; // Ancienne valeur de l'état du bouton

// Variables pour eviter les rebons lors de l'appui sur le bouton
unsigned long oldMillis = 0;           // Ancienne valeur de temps 
unsigned long delaisDebounce = 200;    // Ne pas considérer d'appui sur le bouton s'il sont distant de moins de 200 ms

unsigned long countdownSetupScreen;   //
unsigned long shutterStartCountdown = 0;

// Temps d'affichage du setup
int delaisCountdown = 5000;
// Nombre de photos prises
int nbShots  = 0;
// Délai d'evoi de l'impulsion à l'appareil photo, par défaut 1s, mais cela devrait pouvoir etre inférieur.
int delaiShutter = 1000;
// Nombre de délais parametrés
#define NBDELAIS 8
int tableDelais[ NBDELAIS ] = { 5, 10, 30, 60, 120, 300, 600, 1800 };

// Choix par défaut (index du tableau tableDelais)
int pressed = 0;

// Fonction d'affichage de l'écran de paramétrage
void printSetupScreen( int pressed )
{
       lcd.setCursor(0, 0);
       lcd.print( "Time Set : ");
       lcd.print( tableDelais[ pressed ] );
       lcd.print( "s     ");
       lcd.setCursor(0, 1);
       lcd.print( (int) (3600 / tableDelais[ pressed ]) );
       lcd.print( "/h     ");       
       lcd.setCursor(8, 1);
       lcd.print( (int) (86400 / tableDelais[ pressed ]) );
       lcd.print( "/j     ");             
}

// Fonction d'affichage de l'écran de fonctionnement
void printRunningScreen( unsigned long timeStartShutter, int delai, int shooting, int nbShots )
{
       lcd.setCursor(0, 0);
       lcd.print( int( (millis() - timeStartShutter) / 1000 )  );
       lcd.print( "/");
       lcd.print( delai );
       lcd.print( "            ");
       lcd.setCursor(0, 1);
       if ( shooting == 0 )
       {
         lcd.print( nbShots);
         lcd.print(" photos             " );
       }
       else
       {
          lcd.print( "Shooting           " );
       }

}

void setup() {
  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);      
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);   
  // Activation de la résistance de Pullup pour le bouton
  digitalWrite(buttonPin, HIGH);
  // set up the LCD's number of columns and rows: 
  lcd.begin(16, 2);
  // On affiche l'écran de reglage
  printSetupScreen( pressed );
  // On initialise le timer de l'écran de selection
  countdownSetupScreen = millis();
}

void loop(){
  // read the state of the pushbutton value:
  buttonState = digitalRead(buttonPin);
  unsigned long curMillis = millis();
  
  // Test du bouton, si sa velru à changé
  if ( buttonState != oldButtonState )
  {
    // Teste de "debounce", ne pas tenir compte de pressions trop rapprochées (delaisDebounce ms)
    if ( (oldMillis + delaisDebounce) < curMillis )
    {
      // Si la valeur est LOW c'est qu'on a appuyé sur le bouton
      if (buttonState == LOW) {     

        // Si le bouton a été préssé on incrémente le pointeur de selection du délai
        pressed ++;
        // si on a atteind le dernier element on cycle vers le premier délai disponible dans la liste
        if ( pressed >= ( NBDELAIS ) )
        {
          pressed = 0;
        }
        // On affiche l'écran de réglage
        printSetupScreen( pressed );
        countdownSetupScreen = curMillis;
      }
      // sauvegarde le "moment" actuel pour le debounce
      oldMillis = curMillis;
      //Sauvegarde l'état actuel du bouton
      oldButtonState = buttonState;
      // Remet a zero le timer d'affichage de l'écran de reglage (affichage pendant delaisCountdown ms)
      shutterStartCountdown = 0;
    }
  }
  
  
  // Si delaisCountdown millisecondes sont passées depuis le dernier appui sur le bouton on repasse en mode "Running"
  if ( countdownSetupScreen + delaisCountdown < curMillis )
  {
    // Si le shutterStarCountdown ( heure de démarrage du retardateur entre deux prise de vue) est à zéro on l'initialise à l'heure actuelle
    if ( shutterStartCountdown == 0 )
    {
      shutterStartCountdown = curMillis;
    }

    // Si on a passé plus du délai imparti depuis shutterStarCountdown on prends la photo
    if ( (curMillis - shutterStartCountdown ) >  ( (unsigned long)tableDelais[ pressed ] * 1000) )    
    {
      // Prise de la photo 
      digitalWrite(shutter, HIGH);   // take picture

      // Affichage de l'écran avec l'indication de prise de vue
      printRunningScreen( shutterStartCountdown, tableDelais[ pressed ], 1, nbShots );
      nbShots ++;      
      delay( delaiShutter );
      // Arret de l'ouverture du shutter
      digitalWrite(shutter, LOW);    // release shutter
      
      printRunningScreen( shutterStartCountdown, tableDelais[ pressed ], 0 , nbShots);     
      // Remise à zero du compteur
      shutterStartCountdown = curMillis;
    }
    else
    {
      // Affichage de l'écran 
      printRunningScreen( shutterStartCountdown, tableDelais[ pressed ], 0 , nbShots);
    }
  }
  delay(10);
}
